package org.travel.travel2gether.service;

import java.util.Collections;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.*;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.travel.travel2gether.dao.AccountDao;
import org.travel.travel2gether.domain.Account;
import org.travel.travel2gether.domain.Role;

public class UserService implements UserDetailsService {

	@Autowired
	private AccountDao accountDao;

	@Autowired
	private PasswordEncoder passwordEncoder;

	@PostConstruct
	protected void initialize() {
		saveAccount(new Account("user", "demo", Role.GENERAL));
		saveAccount(new Account("admin", "admin", Role.ADMIN));
	}

	/**
	 * Instead of Spring Data Repository save method, this must be used because
	 * of password encryption.
	 * 
	 * @param account
	 * @return
	 */
	public Account saveAccount(Account account) {
		account.setPassword(passwordEncoder.encode(account.getPassword()));
		accountDao.save(account);
		return account;
	}

	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		Account account = accountDao.findByUsername(username);
		if (account == null) {
			throw new UsernameNotFoundException("user not found");
		}
		return new User(account.getUsername(), account.getPassword(),
				Collections.singleton(createAuthority(account)));
	}

	public void signin(Account account) {
		SecurityContextHolder.getContext().setAuthentication(
				authenticate(account));
	}

	public Account getCurrentAccount() {
		Account account = (Account) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		return accountDao.findByUsername(account.getUsername());
	}

	private Authentication authenticate(Account account) {
		return new UsernamePasswordAuthenticationToken(account, null,
				Collections.singleton(createAuthority(account)));
	}

	private GrantedAuthority createAuthority(Account account) {
		return new SimpleGrantedAuthority(account.getRole().name());
	}

}
